/*
 * transmission.h
 *
 *  Created on: Jul 30, 2010
 *      Author: Pierre Lindenbaum PhD
 *              plindenbaum@yahoo.fr
 *              http://plindenbaum.blogspot.com
 *              
 */

#ifndef TRANSMISSION_H_
#define TRANSMISSION_H_
#include "core/random.h"
#include "pedigree.h"
#include "hapfile.h"

class IndividualHaplotypes
    {
    private:
	const IndividualPtr indi;
	const MarkerListPtr markers;
	std::vector<Haplotype> haplotypes;
public:
	IndividualHaplotypes(const IndividualPtr indi,const MarkerListPtr markers):indi(indi),markers(markers)
	    {
	    }
	virtual ~IndividualHaplotypes()
	    {
	    }

	const Haplotype& Haplotype(int markedIndex) const
	    {
	    return haplotypes.at(markedIndex);
	    }

    };


class IndividualHaplotypesFactory
    {
    private:
	HapFilePtr hapFile;
	RandomPtr random;

	std::vector<const IndividualPtr> individuals;
	int _getIndexForIndividual(const IndividualPtr indi)
	    {
	    for(int i=0;i< individuals.size();++i)
		{
		if(individuals.at(i)==indi) return i;
		}
	    return -1;
	    }

	void makeLove(
		const IndividualPtr child,
		const IndividualHaplotypes* father,
		const IndividualHaplotypes* mother)
	    {
	    LocusList::size_type start_locus=0;
	    IndividualHaplotypes* child=new IndividualHaplotypes();
	    child->markers=hapFile->markers();
	    child->indi=child;
	    child->genotypes.reserve(child->markers->size());

	    bool xcrossFather=random->nextBool();
	    bool xcrossMother=random->nextBool();

	    for(int i=0;i< hapFile->markerCount();++i)
		{
		LocusList::size_type index_locus= locusList->lower_bound(
			start_locus,
			hapFile->markerAt(i)->position()
			);
		double proba_crossover=0.0;
		if(index_locus>0 && index_locus< locusList->size())
		    {
		    //TODO fix position
		    proba_crossover = locusList->at(index_locus)->combined();
		    start_locus=index_locus;
		    }

		if(random()->rnd() < proba_crossover)
			{
			xcrossFather=!xcrossFather;
			};
		if(random()->rnd() < proba_crossover)
			{
			xcrossMother=!xcrossMother;
			};

		Haplotype p1= father->get(i);
		if(xcrossFather) p1=p1.swap();
		Haplotype p2= mother->get(i);
		if(xcrossMother) p2=p2.swap();
		Haplotype c(p1.a0(),p2.a0());
		child->haplotypes.push_back(c);
		}
	    }
    public:

	void setRandom(const RandomPtr random)
	    {
	    this->random=random;

	    }

	void setHapFile(const HapFilePtr hapFile)
	    {
	    this->hapFile=(HapFilePtr)hapFile;
	    individuals.reserve(this->hapFile->individualCount());
	    }

	void setIndividualIndex(const IndividualPtr indi,int index)
	    {
	    assert(_getIndexForIndividual(indi)==-1);

	    while(index>=individuals.size())
		{
		individuals.push_back(NULL);
		}
	    individuals.assign(index,indi);
	    }

	IndividualHaplotypes* get(const IndividualPtr indi)
	    {
	    IndividualHaplotypes* father=NULL;
	    IndividualHaplotypes* mother=NULL;
	    if(indi->hasFather())
		{
		father= get(indi->father());
		}
	    if(indi->hasMother())
		{
		mother= get(indi->mother());
		}
	    crossover(father,mother);
	    }
    };

#endif /* TRANSMISSION_H_ */
